package procesador;

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Vector;


public class ProcessList {

	Process root;//para apuntar al primero proceso
	ArrayList <Process> ListS;//para manejar los procesos que estan en suspencion y envial icono
	ArrayList <Process> ListP;//para manejar los procesos que estan en preparado y envial icono
	Process currentP;//contiene el primer proceso de ListaP
	Process currentS;//contiene el primer proceso de ListaS
	int proPre;//current lista preparados para no exceder los limites de la lista de preparados 
	int proSus;//current lista suspendidos para no exceder los limites de la lista de suspendidos

	public ProcessList() {//metodo constructor

		root=null;//porque no hay elementos aun
		ListS=new ArrayList <Process>();//para identificar el tipo de elementos a guardar 
		ListS=new ArrayList <Process>();//para identificar el tipo de elementos a guardar 

	}

	public void insert(Process node){//inserta el proceso de forma ordenada
		Process aux=root;//para recorrer la lista

		if (root==null){//en caso de  que sea el primer nodo 
			root=node;
		}
		else if (node.state=='I'){//si esta inactivo se agrega al final de la lista
			while(aux.next!=null){
				aux=aux.next;
			}
			aux.next=node;
			node.back=aux;
		}
		else if(node.priority<root.priority){//si tiene menor prioridad que el primer nodo
			node.next=root;
			root.back=node;
			root=node;
		}
		else {//si tiene mayor prioridad que el primero nodo y el proceso no esta inactivo y no es el primer proceso
			while(aux!=null){
				if(node.priority<aux.priority){//si tiene menor prioridad que el proceso actual
					node.next=aux;
					node.back=aux.back;
					aux.back.next=node;
					aux.back=node;
					break;
				}
				else if(node.priority==aux.priority){//si la prioridad es igual a la del proceso actual
					if(node.quantum<root.quantum && node.priority==root.priority){//si tiene igual prioridad y menor 
						node.next=root;											  //quantum que el primer proceso
						root.back=node;
						root=node;
						break;
					}
					else if(node.quantum<aux.quantum){//si tiene menor quantum pero igual prioridad que el actual
						node.next=aux;
						node.back=aux.back;
						aux.back.next=node;
						aux.back=node;
						break;
					}
					else if(node.quantum==aux.quantum){//si tiene igual quantum al del actual
						if(node.pid<root.pid && node.priority<root.priority){// si tiene menor pid y menor 
							node.next=root;									 // prioridad que el primero
							root.back=node;
							root=node;
							break;
						}
						else if(node.pid<aux.pid ){//si tiene menor pid que el actual
							node.next=aux;
							node.back=aux.back;
							aux.back.next=node;
							aux.back=node;
							break;
						}
					}
				}
				aux=aux.next;
			}
			if(aux==null){//si es null entonces el nodo no se enlazo
				aux=root; //y se lo debe enlazar al final porque tiene mayor prioridad, quantum y pid
				while(aux.next!=null){
					aux=aux.next;
				}
				aux.next=node;
				node.back=aux;
			}
		}
	}

	public Process searchState(char st){//busca un proceso segun su estado y 
		Process aux=root;				//regresa el primer proceso que encuentra con el estado especificado
		if(aux==null){//si no hay procesos en la lista
			return null;
		}
		else {
			while(aux!=null){
				if(aux.state==st){//retorna el primero que cumple la condicion
					return aux;
				}
				else {
					aux=aux.next;
				}
			}
		}
		return null;
	}

	public void reorder(){//para reorganizar la lista cuando los procesos se activan 
		Process rootAux=root;//para guardar la lista original
		if(rootAux==null){//si no hay nodos
			return;
		}
		else {
			Process aux=rootAux;//para recorrer la lista original
			root=null;//para reiniciar la lista de nodos
			while(aux!=null){
				Process aux1=new Process(aux.name, aux.addressIcon);//se crea una copia de cada elemento en la lista origina
				aux1.pid=aux.pid;//copia de atributos de los elementos originales
				aux1.priority=aux.priority;
				aux1.icon=aux.icon;
				aux1.quantum=aux.quantum;
				aux1.qt=aux.qt;
				aux1.state=aux.state;
				aux1.suspentionFlag=aux.suspentionFlag;
				aux1.x=aux.x;
				aux1.y=aux.y;
				insert(aux1);//se inserta de forma ordenada el elemento
				aux=aux.next;//avanza en la lista
			}
		}
		remove();//para eliminar los que hayan finalizado


	}

	public void remove(){//elimina los procesos que hayan inalizado
		if(root==null){//si no hay elementos
			return;
		}
		else {
			Process aux=root;//para recorrer la lista
			while(aux!=null){
				if(aux.quantum==0){//si tiene quantum cero
					if(aux==root){// si tiene quantum cero y es el primero
						root=aux.next;
					}
					else if(aux.next==null){//si tiene quantum cero y es el ultimo
						aux.back.next=null;
					}
					else {//si tiene quantum cero y es el actual
						aux.back.next=aux.next;
						aux.next.back=aux.back;
					}
				}
				aux=aux.next;
			}
		}

	}

	public short getListLong(){//retorna el numero de procesos en la lista
		short con=0;
		Process aux=root;
		while(aux!=null){
			con++;
			aux=aux.next;
		}
		return con;

	}

	public String show(){//retorna una cadena con la informacion de cada proceso
		String ret="";
		Process aux=root;
		while(aux!=null){
			ret+="\n";
			ret+=aux.name+" ";
			ret+="Estado: "+aux.state+" ";
			ret+="Quantum: "+aux.quantum+" ";
			ret+="Prioridad: "+aux.priority+" ";
			ret+="PID: "+aux.pid+" ";
			ret+="Prog: "+aux.getProgres()+"% ";
			ret+="Inter: "+aux.suspentionFlag+"% ";
			ret+="qt: "+aux.qt+" ";
			aux=aux.next;
		}

		return ret;
	}

	public Vector<String> fillList(){//crea un vector de strings con algunos datos de cada proceso
		String cad="";				//para llenar la lista de procesos visible en la ventana
		Process aux=root;//primero se crea una cadena con todos los datos
		while(aux!=null){
			cad+=aux.name;
			cad+="%10d"+"Estado: "+aux.state+" ";
			cad+="\tProg: "+aux.getProgres()+"% ";
			cad+="\n";
			aux=aux.next;
		}
		Vector<String> ret;//se crea el vector de cadenas
		ret=new Vector();
		StringTokenizer row= new StringTokenizer(cad,"\n");//se separa cada elemento por un \n
		while(row.hasMoreTokens()){
			ret.add(row.nextToken());
		}
		return ret;//retonrna el vector de cadenas
	}

	public void ListSuspended(){//llena la lista de procesos suspendidos en el momento
		ListS=new ArrayList();
		Process aux=root;//para recorrer la lista
		while(aux!=null){
			if(aux.state=='S'){//si el estado del proceso es suspendido
				ListS.add(aux);//agrega el elemento
			}
			aux=aux.next;
		}
		if(ListS.size()!=0){//verifica si la lista esta vacia
			proSus=0;
			currentS= ListS.get(0);
		}
		else {//si la lista esta vacia
			currentS= null;
		}

	}

	public void ListPreparated(){//llena la lista de procesos preparados en el momento
		ListP=new ArrayList();
		Process aux=root;//para recorrer la lista
		while(aux!=null){
			if(aux.state=='P'){//si el estado del proceso es preparado
				ListP.add(aux);//agrega el elemento
			}
			aux=aux.next;
		}
		if(ListP.size()!=0){//verifica si la lista esta vacia
			proPre=0;
			currentP= ListP.get(0);
		}
		else {//si la lista esta vacia
			currentP= null;
		}
	}

	public Process getXYproces(int x, int y){//busca un proceso segun coordenadas

		Process aux=root;//para recorrer la lista

		while(aux!=null){
			//verifica si las coordenadas enviadas por parametro estan dentro de las coordenadas del Label
			// del elemento actual, si es asi retorna el elemento actual
			if(x>= aux.x-5 && x <= aux.x+40 && y >= aux.y-5 && y <= aux.y+40 && aux.x!=0 && aux.y!=0 ){
				return aux;
			}
			aux=aux.next;
		}

		return aux;
	}

	public Process getCurrentP(){//retorna el primer elemento en preparado
		ListPreparated();//actualiza la lista de preparados
		return currentP;
	}

	public Process getCurrentS(){//retorna el primer elemento en suspendido
		ListSuspended();//actualiza la lista de suspendidos
		return currentS;
	}

	public Process goNextCurrentP(){//retorna el siguien en la lista de preparados
		proPre++;//aumenta el current de la lista de preparados
		if(proPre>=ListP.size()){//verifica si el current se sale de las dimensiones de la lista de preparados
			proPre=0;//el current vuelve al inicio de lal ista de preparados
		}
		if(ListP.size()!=0){//verifica que la lista no este vacia
			return ListP.get(proPre);
		}
		return null;
	}

	public Process goBackCurrentP(){//retorna el anterior en la lista de preparados
		proPre--;//decrementa el current de la lista de preparados
		if(proPre<0){//verifica si el current se sale de las dimensiones de la lista de preparados
			proPre=ListP.size()-1;//el current va al final de la lista de preparados
		}
		if(ListP.size()!=0){//verifica que la lista no este vacia
			return ListP.get(proPre);
		}
		return null;
	}

	public Process goNextCurrentS(){//retorna el siguien en la lista de suspendidos
		proSus++;//aumenta el current de la lista de suspendidos
		if(proSus>=ListS.size()){//verifica si el current se sale de las dimensiones de la lista de suspendidos
			proSus=0;//el current vuelve al inicio de lal ista de suspendidos
		}
		if(ListS.size()!=0){//verifica que la lista no este vacia
			return ListS.get(proSus);
		}
		return null;
	}

	public Process goBackCurrentS(){//retorna el anterior en la lista de suspendidos
		proSus--;//decrementa el current de la lista de suspendidos
		if(proSus<0){//verifica si el current se sale de las dimensiones de la lista de suspendidos
			proSus=ListS.size()-1;//el current va al final de la lista de suependidos
		}
		if(ListS.size()!=0){//verifica que la lista no este vacia
			return ListS.get(proSus);
		}
		return null;
	}

}
